package it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyScrollPanel;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.Widget;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FMouseListener;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyListeners.FMouseListenerHandler;
import it.fuzzylogics.fuzzywidgetsLibrary.client.FuzzyPNGImage.FPNGImage;

public class HBar extends HorizontalPanel {

    int arrowWidth = 20;
    int arrowHeight = 20;
    FPNGImage leftArrow;
    FPNGImage rightArrow;
    AbsolutePanel central;
    Cursor cursor;
    boolean moveIt = false;
    int realCursorWidth;
    boolean hasFixedWidth = false;


    private FScrollListenerCollection scrollListenerCollection;
    private int childWidth;

    public HBar() {


        cursor = new Cursor();
        cursor.setPixelSize(arrowWidth, 50);
        cursor.setStyleName("fuzzy-hBarCursor");

        central = new AbsolutePanel() {

            public void onBrowserEvent(Event event) {

                if (DOM.isOrHasChild(this.getElement(), DOM.eventGetTarget(event))) {
                    DOM.eventPreventDefault(event);
                }
            }
        };
        central.sinkEvents(Event.ONMOUSEDOWN);
        central.setStyleName("fuzzy-hBarCentral");
        central.add(cursor);

        leftArrow = new FPNGImage();
        rightArrow = new FPNGImage();
        leftArrow.setPixelSize(arrowWidth, arrowHeight);
        rightArrow.setPixelSize(arrowWidth, arrowHeight);
        add(leftArrow);
        add(central);
        add(rightArrow);

        setStyleName("fuzzy-hBar");

        addCursorMoveListener();
        addArrowsMouseListeners();

        scrollListenerCollection = new FScrollListenerCollection();
    }


    private void addCursorMoveListener() {


        cursor.addMouseListener(new MouseListener() {
            int dragStartX
                    ,
                    dragStartY
                    ,
                    widgetLeft;

            public void onMouseDown(Widget widget, int i, int i1) {
                moveIt = true;
                DOM.setCapture(widget.getElement());
                dragStartX = i;
                dragStartY = i1;


            }

            public void onMouseEnter(Widget widget) {
            }

            public void onMouseLeave(Widget widget) {
            }

            public void onMouseMove(Widget widget, int i, int i1) {

                widgetLeft = central.getWidgetLeft(cursor);

                int left = i + widgetLeft;

                if (moveIt) {

                    if ((left - dragStartX) >= 0 && ((left - dragStartX) + realCursorWidth) <= (central.getOffsetWidth())) {
                        central.setWidgetPosition(cursor, left - dragStartX, central.getWidgetTop(cursor));


                        scrollListenerCollection.fireOnScroll(calculateDispacement());


                    } else if ((left - dragStartX) < 0) {
                        central.setWidgetPosition(cursor, 0, central.getWidgetTop(cursor));
                        scrollListenerCollection.fireOnScroll(0);
                    } else if (((left - dragStartX) + realCursorWidth) > (central.getOffsetWidth())) {
                        central.setWidgetPosition(cursor, (central.getOffsetWidth() - realCursorWidth), central.getWidgetTop(cursor));


                        scrollListenerCollection.fireOnScroll(calculateDispacement());

                    }
                }
            }

            public void onMouseUp(Widget widget, int i, int i1) {
                moveIt = false;
                DOM.releaseCapture(widget.getElement());
            }
        });

    }

    private void addArrowsMouseListeners() {
        final Timer leftArrowTimer = new Timer() {

            public void run() {
                int pos = central.getWidgetLeft(cursor) - central.getOffsetWidth() / 100;

                if (pos <= 0) {
                    central.setWidgetPosition(cursor, 0, central.getWidgetTop(cursor));
                    scrollListenerCollection.fireOnScroll(0);
                } else {
                    central.setWidgetPosition(cursor, pos, central.getWidgetTop(cursor));
                    scrollListenerCollection.fireOnScroll(calculateDispacement());
                }


            }
        };
        final Timer rightArrowTimer = new Timer() {

            public void run() {
                int pos = central.getWidgetLeft(cursor) + central.getOffsetWidth() / 100;

                if ((pos + realCursorWidth) > (central.getOffsetWidth())) {
                    central.setWidgetPosition(cursor, (central.getOffsetWidth() - realCursorWidth), central.getWidgetTop(cursor));
                    scrollListenerCollection.fireOnScroll(calculateDispacement());
                } else {
                    central.setWidgetPosition(cursor, pos, central.getWidgetTop(cursor));
                    scrollListenerCollection.fireOnScroll(calculateDispacement());
                }


            }
        };


        FMouseListener.setMouseEvent(leftArrow.getElement(), new FMouseListenerHandler() {

            public void onClick() {

            }

            public void onMouseDown(int i, int i1) {
                leftArrowTimer.run();
                leftArrowTimer.scheduleRepeating(20);
            }

            public void onMouseEnter() {
                leftArrowTimer.run();
                leftArrowTimer.scheduleRepeating(20);
            }

            public void onMouseLeave() {
                leftArrowTimer.cancel();
            }

            public void onMouseUp(int i, int i1) {
                leftArrowTimer.cancel();
            }

            public void onMouseWheelUp(int intensity) {

            }

            public void onMouseWheelDown(int intensity) {

            }

            public void onMouseMove(int x, int y) {

            }
        });
        FMouseListener.setMouseEvent(rightArrow.getElement(), new FMouseListenerHandler() {

            public void onClick() {

            }

            public void onMouseDown(int i, int i1) {
                rightArrowTimer.run();
                rightArrowTimer.scheduleRepeating(20);
            }

            public void onMouseEnter() {
                rightArrowTimer.run();
                rightArrowTimer.scheduleRepeating(20);
            }

            public void onMouseLeave() {
                rightArrowTimer.cancel();
            }

            public void onMouseUp(int i, int i1) {
                leftArrowTimer.cancel();
            }

            public void onMouseWheelUp(int intensity) {
                rightArrowTimer.cancel();
            }

            public void onMouseWheelDown(int intensity) {

            }

            public void onMouseMove(int x, int y) {

            }
        });


    }

    public void setFixedCursorSizeAndPosition(int w, int h, int x, int y) {
        hasFixedWidth = true;
        cursor.setPixelSize(w, h);
        central.setWidgetPosition(cursor, x, y);
    }

    public void setHorizontalBarHeight(int h) {
        arrowHeight = h;
        arrowWidth = h;
    }

    public int getScrollPosition() {
        return calculateDispacement();
    }

    public void resetScrollPosition() {
        central.setWidgetPosition(cursor, 0, 0);
        scrollListenerCollection.fireOnScroll(calculateDispacement());
    }


    public void setWidth(String w) {
        super.setWidth(w);
        int width = Integer.parseInt(w.replace("px", ""));
        central.setWidth((width - (2 * arrowWidth)) + "px");
        central.setHeight(arrowHeight + "px");
        rightArrow.setWidth(arrowWidth + "px");
        leftArrow.setWidth(arrowWidth + "px");
    }

    public void setHeight(String h) {
        super.setHeight(arrowHeight + "px");
        int height = Integer.parseInt(h.replace("px", ""));
        central.setHeight(arrowHeight + "px");

    }

    public void setLeftArrowImageUrl(String url) {
        leftArrow.setUrl(url);
        addArrowsMouseListeners();
        leftArrow.setPixelSize(arrowWidth, arrowHeight);
    }

    public void setRightArrowImageUrl(String url) {
        rightArrow.setUrl(url);
        addArrowsMouseListeners();
        rightArrow.setPixelSize(arrowWidth, arrowHeight);
    }

    public int getArrowWidth() {
        return arrowWidth;
    }

    public int getArrowHeight() {
        return arrowHeight;
    }

    public void setCursorWidth(int childWidth) {

        this.childWidth = childWidth;

        double centralW = central.getOffsetWidth();
        double arrowW = arrowWidth;
        double childW = childWidth;

        double cursorWidth = ((centralW + (2 * arrowW)) / childW * (centralW));
        realCursorWidth = (int) cursorWidth;

        if (cursorWidth >= central.getOffsetWidth()) {
            return;
        }

        cursor.setPixelSize((int) cursorWidth, arrowHeight);
        scrollListenerCollection.fireOnScroll(calculateDispacement());
    }

    public void addScrollListener(FScrollListener l) {
        scrollListenerCollection.add(l);
    }

    public void removeScrollListener(FScrollListener l) {
        scrollListenerCollection.remove(l);
    }

    private int calculateDispacement() {
        int maxOffset = childWidth - (central.getOffsetWidth() + (2 * arrowWidth));

        double ratio = ((double) central.getOffsetWidth()) / ((double) realCursorWidth);

        double jump = maxOffset - (((double) central.getOffsetWidth() - (double) realCursorWidth)) * ratio;

        double offset = ((double) central.getWidgetLeft(cursor)) * ratio;
        offset += jump * ((double) central.getWidgetLeft(cursor)) / (((double) central.getOffsetWidth() - (double) realCursorWidth));

        return (int) offset;
    }


}
